﻿namespace Mohe.Scada.Util.GA
{
    /// <summary>
    /// 槽负载
    /// </summary>

    public class TankLoad
    {
        public int TankId { get; set; }
        public int TotalUsageTime { get; set; }
    }
    /// <summary>
    /// 定义工序类
    /// </summary>
    public class Process
    {
        public int TaskId { get; set; }
        public int ProcessId { get; set; }
        public List<int> TankIds { get; set; }
        public int Duration { get; set; }

        public int MaxAllowedTimeInTank { get; set; }
        public int SelectedTank { get; set; }

    }


    /// <summary>
    /// 定义染色体类
    /// </summary>
    public class Chromosome
    {
        public List<Tuple<int, int>> Gene { get; set; } //工序与行车索引
        public double Fitness { get; set; }

        public int IdleMoveTime { get; set; }

        public int TotalOverTimeInTank { get; set; }

    }

    public class Task
    {
        public int TaskId { get; set; }

        public List<Process> Processes { get; set; }
    }

    public class Crane
    {
        public int CraneId { get; set; }
        public int CurrentPosition { get; set; }
        public bool IsIdle { get; set; }
        public List<int> AllowedTanks { get; set; } // 允许运动的槽集合
    }
    /// <summary>
    /// 遗传算法
    /// </summary>
    public class GeneticAlgorithm
    {
        public List<Task> tasks;
        public int populationSize = 100;
        private double crossoverRate = 0.8;
        private double mutationRate = 0.2;
        public int generations = 500;
        private const double INVALID_SCHEDULE_PENALTY = 1e10; // 无效调度方案的惩罚值
        public List<Crane> cranes;
        private double fitnessThreshold = 0.01;

        public GeneticAlgorithm(List<Task> tasks, int craneCount)
        {
            this.tasks = tasks;
            this.cranes = Enumerable.Range(1, craneCount)
                       .Select(id => new Crane { CraneId = id, CurrentPosition = 1, IsIdle = true })
                       .ToList();
        }

        public GeneticAlgorithm(List<Task> tasks, int populationSize, double crossoverRate, double mutationRate, int generations, int craneCount)
        {
            this.tasks = tasks;
            this.populationSize = populationSize;
            this.crossoverRate = crossoverRate;
            this.mutationRate = mutationRate;
            this.generations = generations;
            this.cranes = Enumerable.Range(1, craneCount)
                       .Select(id => new Crane { CraneId = id, CurrentPosition = 1, IsIdle = true })
                       .ToList();
        }

        // 假设根据车间布局获取从当前槽到目标槽的移动时间
        private int GetTravelTime(int currentTank, int targetTank)
        {
            // 这里只是示例，实际应根据车间布局计算
            return Math.Abs(currentTank - targetTank);
        }

        // 计算总生产时间并记录空载移动时间和在槽超时时间
        private double CalculateMakespan(List<Tuple<int, int>> gene, out int idleMoveTime, out int totalOverTimeInTank, out double tankLoadVariance)
        {
            List<TankLoad> tankLoads = tasks.SelectMany(t => t.Processes.SelectMany(p => p.TankIds).Distinct())
                                        .Select(tankId => new TankLoad { TankId = tankId, TotalUsageTime = 0 }).ToList();
            idleMoveTime = 0;
            totalOverTimeInTank = 0;
            tankLoadVariance = 0;
            int totalTime = 0;
            var craneStates = cranes.Select(c => new { c.CraneId, c.CurrentPosition, c.IsIdle }).ToList();

            foreach (var (processIndex, craneIndex) in gene)
            {
                int taskIndex = processIndex / tasks[0].Processes.Count;
                int processInTaskIndex = processIndex % tasks[taskIndex].Processes.Count;
                Process process = tasks[taskIndex].Processes[processInTaskIndex];

                var minLoadTank = tankLoads.Where(t => process.TankIds.Contains(t.TankId)).OrderBy(t => t.TotalUsageTime).First();
                process.SelectedTank = minLoadTank.TankId;

                if (!cranes[craneIndex].AllowedTanks.Contains(process.SelectedTank))
                {
                    return INVALID_SCHEDULE_PENALTY;
                }

                minLoadTank.TotalUsageTime += process.Duration;

                var currentCrane = craneStates[craneIndex];
                if (currentCrane.IsIdle)
                {
                    int travelTime = GetTravelTime(currentCrane.CurrentPosition, process.SelectedTank);
                    idleMoveTime += travelTime;
                    totalTime += travelTime;
                }
                else
                {
                    // 这里简单假设如果行车忙，则等待直到其空闲
                    totalTime += GetTravelTime(currentCrane.CurrentPosition, process.SelectedTank);
                }
                craneStates[craneIndex] = new { CraneId = currentCrane.CraneId, CurrentPosition = process.SelectedTank, IsIdle = false };

                if (processInTaskIndex == 0)
                {
                    // 开始任务
                }
                if (processInTaskIndex == tasks[taskIndex].Processes.Count - 1)
                {
                    craneStates[craneIndex] = new { CraneId = currentCrane.CraneId, CurrentPosition = process.SelectedTank, IsIdle = true };
                    int actualTimeInTank = totalTime - (processInTaskIndex == 0 ? totalTime : 0) + process.Duration;
                    if (actualTimeInTank > process.MaxAllowedTimeInTank)
                    {
                        totalOverTimeInTank += actualTimeInTank - process.MaxAllowedTimeInTank;
                    }
                }

                totalTime += process.Duration;
            }

            double averageLoad = tankLoads.Average(t => t.TotalUsageTime);
            tankLoadVariance = tankLoads.Average(t => Math.Pow(t.TotalUsageTime - averageLoad, 2));

            return totalTime;
        }

        // 计算适应度，考虑空载率、在槽超时和槽负载平衡
        public void CalculateFitness(List<Chromosome> population)
        {
            double idleWeight = 0.3;
            double overTimeWeight = 0.2;
            double tankLoadWeight = 0.1;

            foreach (var chromosome in population)
            {
                int idleMoveTime;
                int totalOverTimeInTank;
                double tankLoadVariance;
                double makespan = CalculateMakespan(chromosome.Gene, out idleMoveTime, out totalOverTimeInTank, out tankLoadVariance);
                if (makespan == INVALID_SCHEDULE_PENALTY)
                {
                    chromosome.Fitness = 0;
                }
                else
                {
                    chromosome.IdleMoveTime = idleMoveTime;
                    chromosome.TotalOverTimeInTank = totalOverTimeInTank;

                    double weightedTime = makespan + idleWeight * idleMoveTime + overTimeWeight * totalOverTimeInTank + tankLoadWeight * tankLoadVariance;
                    chromosome.Fitness = 1.0 / weightedTime;
                }
            }
        }

        // 初始化种群
        public List<Chromosome> InitializePopulation()
        {
            List<Chromosome> population = new List<Chromosome>();
            int totalProcesses = tasks.Sum(t => t.Processes.Count);
            int craneCount = cranes.Count;
            for (int i = 0; i < populationSize; i++)
            {
                var gene = Enumerable.Range(0, totalProcesses)
                                 .Select(processIndex => Tuple.Create(processIndex, new Random().Next(0, craneCount)))
                                 .OrderBy(x => Guid.NewGuid()).ToList();
                population.Add(new Chromosome { Gene = gene });
            }
            return population;
        }

        // 选择操作（轮盘赌选择）
        public Chromosome SelectParent(List<Chromosome> population)
        {
            double totalFitness = population.Sum(c => c.Fitness);
            double r = new Random().NextDouble() * totalFitness;
            double sum = 0;
            foreach (var chromosome in population)
            {
                sum += chromosome.Fitness;
                if (sum >= r)
                {
                    return chromosome;
                }
            }
            return population.Last();
        }

        // 交叉操作（顺序交叉）
        public Chromosome Crossover(Chromosome parent1, Chromosome parent2)
        {
            if (new Random().NextDouble() > crossoverRate)
            {
                return parent1;
            }

            int start = new Random().Next(0, parent1.Gene.Count);
            int end = new Random().Next(start, parent1.Gene.Count);

            var childGene = new List<Tuple<int, int>>();
            for (int i = 0; i < parent1.Gene.Count; i++)
            {
                if (i >= start && i <= end)
                {
                    childGene.Add(parent1.Gene[i]);
                }
                else
                {
                    childGene.Add(null);
                }
            }

            int index = 0;
            for (int i = 0; i < parent2.Gene.Count; i++)
            {
                if (!childGene.Contains(parent2.Gene[i]))
                {
                    while (childGene[index] != null)
                    {
                        index++;
                    }
                    childGene[index] = parent2.Gene[i];
                }
            }

            return new Chromosome { Gene = childGene };
        }

        // 变异操作（交换变异）
        public void Mutate(Chromosome chromosome)
        {
            if (new Random().NextDouble() > mutationRate)
            {
                return;
            }

            int index1 = new Random().Next(0, chromosome.Gene.Count);
            int index2 = new Random().Next(0, chromosome.Gene.Count);

            var temp = chromosome.Gene[index1];
            chromosome.Gene[index1] = chromosome.Gene[index2];
            chromosome.Gene[index2] = temp;
        }
        // 遗传算法主循环
        public Chromosome Run()
        {
            var population = InitializePopulation();
            double previousBestFitness = double.MaxValue;
            for (int i = 0; i < generations; i++)
            {
                CalculateFitness(population);
                var newPopulation = new List<Chromosome>();
                for (int j = 0; j < populationSize; j++)
                {
                    var parent1 = SelectParent(population);
                    var parent2 = SelectParent(population);
                    var child = Crossover(parent1, parent2);
                    Mutate(child);
                    newPopulation.Add(child);

                }
                double bestFitness = newPopulation.Min(s => s.Fitness);
                var bestSchedule = newPopulation.First(s => s.Fitness == bestFitness);

                if (Math.Abs(bestFitness - previousBestFitness) < fitnessThreshold)
                {
                    break;
                }
                previousBestFitness = bestFitness;
                population = newPopulation;
            }

            CalculateFitness(population);
            return population.OrderByDescending(c => c.Fitness).First();
        }
    }
}
